<?php
/**
 * Unfuddle API Request
 * This class represents a request to the Unfuddle API. Requests are passed to
 * the Unfuddle_Api::dispatch() method, from which an Unfuddle_Response is
 * returned.
 *
 * @package     Unfuddle
 * @subpackage  API Request
 * @author      Luke Visinoni <luke.visinoni@gmail.com>
 * @copyright   (c) 2010 Luke Visinoni <luke.visinoni@gmail.com>
 * @version     $Id: Request.php 32 2011-05-09 07:42:08Z luke.visinoni $
 */
class Unfuddle_Request extends Unfuddle_Http {

    /**
     * @var string Request method (GET, POST, PUT or DELETE)
     */
    protected $_method;
    
    /**
     * @var string The uri to make the request to (without domain)
     */
    protected $_uri;
    
    /**
     * @var array A list of query parameters to apply to the request
     */
    protected $_query = array();
    
    /**
     * @var array A list of post parameters to send with the request
     */
    protected $_post = array();
    
    /**
     * @var array A list of allowed request methods
     */
    protected $_methods = array('GET', 'POST', 'PUT', 'DELETE');
    
    /**
     * Class constructor
     * When initializing a request object, the only required information is URI
     *
     * @param  string The request uri
     * @param  string The request method (defaults to GET)
     * @param  array  A list of request headers (defaults empty )
     * @return void
     * @todo   Should the URI default to empty? Is a URI really a requirement?
     */
    public function __construct($uri, $method = 'GET', $headers = array()) {
    
        $this->setUri($uri)
             ->setMethod($method)
             ->setHeaders($headers);
    
    }
    
    /**
     * Set the URI for this request
     *
     * @param string Request URI
     * @return $this
     */
    public function setUri($uri) {
    
        $this->_uri = $uri;
        return $this;
    
    }
    
    /**
     * Get the URI for this request (including query string)
     *
     * @return string The request URI
     */
    public function getUri() {
    
        return '/' . ltrim($this->_uri, '/') . $this->getQueryString();
    
    }
    
    /**
     * Set the request method
     *
     * @param string The request method (GET, POST, PUT or DELETE)
     * @return $this
     */
    public function setMethod($method) {
    
        $method = strtoupper($method);
        if (!in_array($method, $this->_methods)) {
            throw new Unfuddle_Request_Exception("{$method} is not a valid request method.");
        }
        $this->_method = $method;
        return $this;
    
    }
    
    /**
     * Get the request method
     *
     * @return string The request method
     */
    public function getMethod() {
    
        return $this->_method;
    
    }
    
    /**
     * Set a query param
     *
     * @param string The name of the query param
     * @param string The value of the query param
     * @return $this
     * @todo Should name and value be validated in any way? Also probably should write tests to make sure of string conversion
     */
    public function setQueryParam($name, $value) {
    
        $this->_query[(string) $name] = (string) $value;
        return $this;
    
    }
    
    /**
     * Get a query param by name
     *
     * @param string The query parameter you want to retrieve
     * @return string The query parameter value
     */
    public function getQueryParam($name) {
    
        if (array_key_exists($name, $this->_query)) {
            return $this->_query[$name];
        }
        // @todo Is this excessive?
        throw new Unfuddle_Request_Exception("{$name} is not a query parameter.");
    
    }
    
    /**
     * Set the query params
     * Rather than setting the query params individually using the above setter,
     * you can also set the params all at one using this method.
     *
     * @param Array A list of query parameters to set all at once
     * @return $this
     */
    public function setQueryParams(Array $params) {
    
        foreach ($params as $name => $value) {
            $this->setQueryParam($name, $value);
        }
        return $this;
    
    }
    
    public function getQueryParams() {
    
        return $this->_query;
    
    }
    
    /**
     * Get the entire query string (including question mark at the beginning)
     *
     * @return string The query string (name/value pairs separated by amperstands and prepended with a question mark)
     */
    public function getQueryString() {
    
        $string = '';
        if (!empty($this->_query)) {
            $pairs = array();
            foreach ($this->_query as $name => $value) {
                $pairs[] = "{$name}={$value}";
            }
            $string .= '?' . implode('&', $pairs);
        }
        return $string;
    
    }
    
    /**
     * Get the entire request as a string
     * This is what a raw HTTP request will look like. Browsers see requests like this.
     *
     * @return string The raw HTTP request
     */
    public function __toString() {
    
        return $this->getMethod() . " " . $this->getUri() . " " . self::HTTP_VERSION ."\r\n" . $this->getHeadersAsString() . "\r\n" . $this->getBody();
    
    }

}
